import json
import threading
import time
from datetime import datetime,timedelta
import hmac
import hashlib
import base64
import urllib.parse
import requests
import tkinter as tk
from tkinter import messagebox, simpledialog
from lunar_python import Lunar, Solar
import common
from logPage import logPage


class Controller:
    # 导入UI类后，替换以下的 object 类型，将获得 IDE 属性提示功能
    ui: object
    def __init__(self):
        pass
    def init(self, ui):
        """
        得到UI实例，对组件进行初始化配置
        """
        self.ui = ui
        # TODO 组件初始化 赋值操作
        # a + b = 2 的时候进行上报
        self.escalation_a = 0  # 生日计算

        self.sql_date_data = []
        self.dingding_url = ""   #钉钉链接
        self.dingding_secret = ""   #钉钉链接密匙
        self.birthday_day = 3 #天  提前多少天提醒
        self.birthday_timea = 820  #开始时间        0820  24小时
        self.birthday_timeb = 850  #不能超过这个时间  0850  24小时
        self.birthday_timec = 1    #清空时间区间a    0001  24小时
        self.birthday_timed = 30   #清空时间区间b    0030  24小时
        self.report_url = ""   #主机状态上报地址
        self.user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
        self.report_frequency = 120  #秒  多少秒访问链接一次
        self.initializationInfo()
        self.configurationJudgment()
        self.showCurrentTime()
        self.sr_monitor_running = False

    def initializationInfo(self):
        #表格
        self.reassignValue()
        self.readConfigurationFileInDatabase()

    def configurationJudgment(self):
        if not self.dingding_url:
            messagebox.showwarning("警告", "钉钉链接未填写，请在填写后保存")
        if not self.dingding_secret:
            messagebox.showwarning("警告", "钉钉链接密匙未填写，请在填写后保存")
        if not self.report_url:
            messagebox.showwarning("警告", "上报链接未填写，请在填写后保存")

    #统计累计时间
    def calculateCumulativeTime(self,runningTimea):
        #n天n小时n分种n秒
        # 计算天数
        days = runningTimea // (24 * 3600)
        runningTimea %= (24 * 3600)
        # 计算小时数
        hours = runningTimea // 3600
        runningTimea %= 3600
        # 计算分钟数
        minutes = runningTimea // 60
        runningTimea %= 60
        # 计算秒数
        seconds = runningTimea

        # print(f"{days}天{hours}小时{minutes}分种{seconds}秒")
        return f"{days}天{hours}小时{minutes}分种{seconds}秒"

    def birthdayCalculation(self,evt):
        if self.sr_monitor_running == True:
            return # 如果监控已经在运行，则不执行任何操作
        # 创建一个线程来更新
        frequency = int(self.report_frequency)
        _con = ""
        self.sr_thread = threading.Thread(target=self.update_sr, args=(_con,frequency))
        self.sr_thread.daemon = True
        self.sr_thread.start()
        self.ui.tk_button_m371c3ii.config(state=tk.DISABLED)  # 禁用按钮
        self.sr_monitor_running = True
        # print("<Button-1>事件未处理:",evt)

    def update_sr(self, _con, frequency):
        _runningTimea = 0
        _subTimea = frequency
        # 不检查停止信号，直接永久循环
        while True:
            #运行时间计算
            _runningTimea += 1
            _strRuna=self.calculateCumulativeTime(_runningTimea)
            self.ui.tk_label_m371ozg3.config(text="运行时间：" + _strRuna)

            _subTimea += 1
            if _subTimea >= frequency:
                current_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
                #生日处理
                cons = self.riri(self.report_url)
                self.ui.tk_label_m371btvf.config(text=f"{current_time}：生日持续提醒中...")
                self.slogWrit(1, current_time , "生日【" + cons + "】")
                _subTimea = 0

            time.sleep(1)

    def reassignValue(self):
        """
         #name  名称
         #type 1农历 2公历
         #month 月份
         #days 日期
         #status 0没发送成功  1发送成功，每天凌晨清空
         #del 1启用0不启用
        """
        for item in self.ui.tk_table_data_list.get_children():
            self.ui.tk_table_data_list.delete(item)
        self.sql_date_data = common.query_data(f"select * from push_time;",2)
        for itm in self.sql_date_data:
            self.ui.tk_table_data_list.insert("", tk.END, values=itm)

    #读取数据库中的配置文件
    # 网址  和  计算、访问频率
    def readConfigurationFileInDatabase(self):
        ini = common.query_data(f"select * from push_configuration ;",1)
        if not ini:
            ini = ('dingding','secret',4,820,850,1,30,'https://www.ip.cn/api/index?ip&type=0','Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',20)
            sql = (f"insert into push_configuration (dingding_url,dingding_secret,birthday_day,birthday_timea,birthday_timeb,birthday_timec,birthday_timed,report_url,user_agent,report_frequency) "
                   f"values {ini};")
            common.sqllite_create(sql)
        self.dingding_url = ini[0]
        self.dingding_secret = ini[1]
        self.birthday_day = int(ini[2])
        self.birthday_timea = int(ini[3])
        self.birthday_timeb = int(ini[4])
        self.birthday_timec = int(ini[5])
        self.birthday_timed = int(ini[6])
        self.report_url = ini[7]
        self.user_agent = ini[8]
        self.report_frequency = int(ini[9])
        self.updateConfigurationInterface()

    #保存配置
    def saveKey(self,event):
        _inisave = messagebox.askokcancel("确认", "你确定要修改配置吗？")
        if _inisave:
            _report_url = self.ui.tk_input_m371mc8q.get()
            _user_agent = self.ui.tk_input_m371mumr.get()
            _dingding_url = self.ui.tk_input_m371z7ob.get()
            _birthday_day = self.ui.tk_input_m4cgzy5s.get()
            _dingding_secret = self.ui.tk_input_m4cgza27.get()
            _report_frequency = self.ui.tk_input_m4ch02ls.get()
            _birthday_timea = self.ui.tk_input_m4ch06iw.get()
            _birthday_timeb = self.ui.tk_input_m4ch09if.get()
            _birthday_timec = self.ui.tk_input_m4ch0e3z.get()
            _birthday_timed = self.ui.tk_input_m4ch0hh4.get()
            common.sqllite_create(f"DELETE FROM push_configuration WHERE dingding_url != ''")
            ini = (_dingding_url, _dingding_secret, int(_birthday_day), int(_birthday_timea), int(_birthday_timeb), int(_birthday_timec), int(_birthday_timed), _report_url,_user_agent,int(_report_frequency))
            sql = (
                f"insert into push_configuration (dingding_url,dingding_secret,birthday_day,birthday_timea,birthday_timeb,birthday_timec,birthday_timed,report_url,user_agent,report_frequency) "
                f"values {ini};")
            common.sqllite_create(sql)
            self.readConfigurationFileInDatabase()
            messagebox.showwarning("提示", "配置修改成功！")

    #更新界面
    def updateConfigurationInterface(self):
        input_boxes=[
            "tk_input_m371mc8q","tk_input_m371mumr",
            "tk_input_m371z7ob","tk_input_m4cgzy5s",
            "tk_input_m4cgza27","tk_input_m4ch02ls",
            "tk_input_m4ch06iw","tk_input_m4ch09if",
            "tk_input_m4ch0e3z","tk_input_m4ch0hh4",
        ]
        iniArr=[
            self.report_url,self.user_agent,
            self.dingding_url,self.birthday_day,
            self.dingding_secret,self.report_frequency,
            self.birthday_timea,self.birthday_timeb,
            self.birthday_timec,self.birthday_timed,
        ]
        for box in input_boxes:
            getattr(self.ui, box).delete(0, tk.END)
            getattr(self.ui, box).insert(0, iniArr[input_boxes.index(box)])

    def riri(self,furl):
        self.escalation_a = 1
        self.accessReport(furl)
        # 获取当前时间
        now = datetime.now()
        shijian = int(f"{now.hour}{now.minute:02d}")

        if shijian > self.birthday_timeb:
            # 超过8点50就不处理了
            print("超过处理")
            return f"已经超过处理{self.birthday_timeb}时间"
        if shijian > self.birthday_timec and shijian < self.birthday_timed:
            # 凌晨清空发送记录 更新表格
            self.clear_send_records()
            self.reassignValue()
            print("清零")
            return f"大于{self.birthday_timec}小于{self.birthday_timed}时间开始清零"
        # 发送时间是8点20 - 8点50 之间
        if shijian < self.birthday_timea:
            print("未到处理")
            return f"未到处理{self.birthday_timea}时间"
        # 今天时间
        year = now.year
        month = now.month
        date = now.day
        # 3天后时间
        time_3 = now + timedelta(days=int(self.birthday_day))
        year_3 = time_3.year
        month_3 = time_3.month
        date_3 = time_3.day

        #农历 获取年、月、日
        #获取阴历月的数字，值从1到12，但闰月为负数，如闰二月=-2
        #所以闰月需要转正数
        ndate = datetime.strptime(f"{year}-{month}-{date}", "%Y-%m-%d")
        n = Lunar.fromDate(ndate)
        ny = n.getYear()
        nm = n.getMonth()
        nd = n.getDay()
        if nm < 0:
            nm = abs(nm)
        n3date = datetime.strptime(f"{year_3}-{month_3}-{date_3}", "%Y-%m-%d")
        n3 = Lunar.fromDate(n3date)
        ny3 = n3.getYear()
        nm3 = n3.getMonth()
        nd3 = n3.getDay()
        if nm3 < 0:
            nm3 = abs(nm3)

        birthdayData = common.query_data(f"select * from push_time where del = 1 and status = 0;",2)
        if  birthdayData:
            for v in birthdayData:
                # type是2
                if v[2] == 1:
                    # 农历
                    lunar_type = "农历"
                    biM = nm
                    biD = nd
                    biM3 = nm3
                    biD3 = nd3
                else:
                    # 默认阳历
                    lunar_type = "阳历"
                    biM = month
                    biD = date
                    biM3 = month_3
                    biD3 = date_3

                # 今日过生 月month是3   日days是4
                if v[3] == biM and v[4] == biD:
                    gregorian_calendar = [year, month, date]
                    lunar_calendar = [ny, nm, nd]
                    str_msg = self.sending_text(1, v[1], gregorian_calendar, lunar_calendar, lunar_type)
                    print(str_msg)
                    if v[5] == 0:
                        self.send_out(str_msg, v[0], 1)

                # 三日后过生
                if v[3] == biM3 and v[4] == biD3:
                    gregorian_calendar = [year_3, month_3, date_3]
                    lunar_calendar = [ny3, nm3, nd3]
                    str_msg = self.sending_text(2, v[1], gregorian_calendar, lunar_calendar, lunar_type)
                    print(str_msg)
                    if v[5] == 0:
                        self.send_out(str_msg, v[0], 2)

            print("提醒成功")
            return f"提醒成功"
        else:
            print("今天无提醒了")
            return f"今天无提醒了"


    def sending_text(self,_type, name, gregorian_calendar, lunar_calendar, lunar_type):
        _str = ''
        if _type == 1:
            _str += f"今天是[{name}]的生日[{lunar_type}]"
            _str += "祝您身体健康、生活甜美\n"
            _str += "生日快乐\n"
            _str += "今天日期为\n"
            _str += f"公历{gregorian_calendar[0]}年{gregorian_calendar[1]}月{gregorian_calendar[2]}日\n"
            _str += f"农历{lunar_calendar[0]}年{lunar_calendar[1]}月{lunar_calendar[2]}日\n"
        elif _type == 2:
            _str += f"{self.birthday_day}天后将是[{name}]的生日[{lunar_type}]\n"
            _str += f"{self.birthday_day}天后日期为\n"
            _str += f"公历{gregorian_calendar[0]}年{gregorian_calendar[1]}月{gregorian_calendar[2]}日\n"
            _str += f"农历{lunar_calendar[0]}年{lunar_calendar[1]}月{lunar_calendar[2]}日\n"
        else:
            _str += "程序出错！"
        return _str
    def send_out(self, str, id, _type):
        fresult = self.dingding_sign(str)
        if fresult == 'ok':
            #更新状态
            sql = "update push_time set status = ?  where id = ?;"
            common.sqllite_update(sql, (1, id))
            #重新赋值查询
            self.reassignValue()
        #写日志
    def clear_send_records(self):
        common.sqllite_create(f"UPDATE push_time SET status=0 WHERE id > 0")
    def dingding_sign(self,content):
        timestamp = str(round(time.time() * 1000))
        #钉钉密匙，需要修改，不能写死
        secret = self.dingding_secret
        secret_enc = secret.encode('utf-8')
        string_to_sign = '{}\n{}'.format(timestamp, secret)
        string_to_sign_enc = string_to_sign.encode('utf-8')
        hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
        sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
        ddUrl = f"{self.dingding_url}" + "&timestamp=" + timestamp + "&sign=" + sign
        data = {
            'at':
                {
                    'atUserIds': [],
                    'atMobiles': [],
                    'isAtAll': True,
                },
            'text': {
                'content': content
            },
            'msgtype': 'text',
        }
        headers = {
            "Content-Type": "application/json",
            "User-Agent": self.user_agent,
        }
        r = requests.post(url=ddUrl, data=json.dumps(data), headers=headers)
        w = json.loads(r.text)
        if w['errcode'] == 0:
            return "ok"
        else:
            return w['errmsg']

    def accessReport(self,furl):
        content = ""
        if self.escalation_a == 1:
            headers = {
                "User-Agent": self.user_agent,
            }
            try:
                response = requests.get(furl, headers=headers)
                content = response.text
            except Exception as r:
                content = "出现错误！可能原因：断网了。"
            if content:
                current_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
                self.ui.tk_label_m372126q.config(text=f"{current_time}：持续上报中...")
                self.slogWrit(2, current_time, "上报【" + content + "】")
            self.escalation_a = 0
        return content


    #显示当前的时间线程
    def showCurrentTime(self):
        self.time_thread = threading.Thread(target=self.update_time)
        self.time_thread.daemon = True
        self.time_thread.start()
    #1秒更新一次
    def update_time(self):
        #直接永久循环
        while True:
            xq = Solar.fromDate(datetime.now())
            xqs = f"星期" + xq.getWeekInChinese()
            #公历年月日
            gl = Solar.fromDate(datetime.now())
            gls = f"公历：" + str(gl.getYear()) +"-"+ str(gl.getMonth()) +"-"+ str(gl.getDay())
            #农历年月日
            nl = Lunar.fromDate(datetime.now())
            nls = f"农历：" + str(nl.getYear()) +"-"+ str(nl.getMonth()) +"-"+ str(nl.getDay())
            current_time = time.strftime('%H:%M:%S', time.localtime())
            zh = xqs +"  "+ gls +"  "+ nls +"  "+ current_time
            self.ui.tk_label_m3719oj6.config(text=zh)
            time.sleep(1)

    #添加一列
    def on_double_add(self,event):
        sql = f"insert into push_time (name, type,month,days,status,del) values ('名字',1,0,0,0,0);"
        common.sqllite_create(sql)
        new_id = common.query_data(f"select id from push_time order by id desc;")
        self.ui.tk_table_data_list.insert("", "end", values=(new_id, "名字",1,0,0,0,0))

    #删除
    def on_double_del(self,event):
        result = messagebox.askokcancel("确认", "你确定要删除这些数据吗？")
        if result:
            selected_items = self.ui.tk_table_data_list.selection()
            if not selected_items:
                return
            for item in selected_items:
                sql_id = self.ui.tk_table_data_list.item(item, 'values')[0]
                common.sqllite_create(f"DELETE FROM push_time WHERE rowid = {sql_id}")
                self.ui.tk_table_data_list.delete(item)

    #编辑
    def on_double_click(self,event):
        # 获取双击的项
        item = self.ui.tk_table_data_list.identify('item', event.x, event.y)
        if not item:
            return

        # 获取双击的列
        column = self.ui.tk_table_data_list.identify_column(event.x)
        col_id = int(column[1:]) - 1  # 转换为列索引

        if column == "#1":
            messagebox.showwarning("提示", "ID无法修改")
            return

        # 获取当前值
        current_value = self.ui.tk_table_data_list.item(item, 'values')[col_id]

        colMap={
            "#1":"ID",
            "#2":"名称",
            "#3":"农历（1农历 2公历）",
            "#4":"月份（1-12月）",
            "#5":"日期（1-31天）",
            "#6":"状态（0没发送成功  1发送成功）",
            "#7":"启用（1启用0不启用）",
        }
        colSqlMap={
            "#1":"id",
            "#2":"name",
            "#3":"type",
            "#4":"month",
            "#5":"days",
            "#6":"status",
            "#7":"del",
        }
        sql_id = self.ui.tk_table_data_list.item(item, 'values')[0]
        new_value = simpledialog.askstring("编辑", f"请输入新的内容：{colMap[column]}", initialvalue=current_value)

        if new_value is not None:
            if column == "#3" and new_value not in ["1","2"]:
                messagebox.showwarning("提示", "农历字段只能填写1或者2（1农历 2公历）。")
                return
            if column == "#4":
                pass
            if column == "#5":
                pass
            if column in ["#6","#7"] and new_value not in ["1","0"]:
                messagebox.showwarning("提示", "状态、启用字段只能填写1或者0（1启用0不启用）。")
                return
            #更新数据库
            sql = f"update push_time set {colSqlMap[column]} = ? where id = ?;"
            common.sqllite_update(sql, (new_value, sql_id))
            # 更新值
            values = list(self.ui.tk_table_data_list.item(item, 'values'))
            values[col_id] = new_value
            self.ui.tk_table_data_list.item(item, values=values)

    def slogWrit(self,type,time_str,details):
        # 获取当前时间的毫秒数
        current_time_ms = int(time.time() * 1000)
        # 截取前11位作为11位时间戳
        timestamp_11 = current_time_ms % 10 ** 11
        sql = f"insert into push_logs (time_occurrence,time_str,details,type) values ({timestamp_11},'{time_str}','{details}',{type});"
        common.sqllite_create(sql)

    #打开日志查询页面
    def newPage(self,event):
        logPage(self.ui)




